//////////////////////////////////////////////////////////////////////////
#include <Script/Script.hpp>
#include <FileSystem/FileSystem.hpp>


//////////////////////////////////////////////////////////////////////////
// Redirect lua print to LOG( INFO ).
extern "C"
int luaPrint( lua_State* l )
{
	std::string	logString;
	int	nargs	=	lua_gettop( l );
	for( int i=1; i<=nargs; ++i )
	{
		switch( lua_type( l, i ) )
		{
		case LUA_TNIL:
			logString	+=	"nil";
			break;
		case LUA_TNUMBER:
			logString	+=	std::to_string( lua_tonumber( l, i ) );
			break;
		case LUA_TBOOLEAN:
			logString	+=	(lua_toboolean( l, i ) ? "true" : "false");
			break;
		case LUA_TSTRING:
			logString	+=	lua_tostring( l, i );
			break;
		case LUA_TTABLE:
			break;
		case LUA_TFUNCTION:
			break;
		case LUA_TUSERDATA:
			break;
		case LUA_TTHREAD:
			break;
		case LUA_TLIGHTUSERDATA:
			break;
		}
	}
	LOG( INFO ) << "Script: " << logString;

	return 0;
}


/*
//////////////////////////////////////////////////////////////////////////
// Redirects do file to use physfs.
extern "C"
int luaDoFile( lua_State* l )
{
	int	nargs	=	lua_gettop( l );
	if( nargs==1 && lua_isstring( l, 1 ) )
	{
		std::string	fileName	=	lua_tostring( l, 1 );
		LOG( INFO ) << "lua dofile: " << fileName;
		std::string	fileContent	=	FileSystem::ReadFileAsString( fileName );

		if( OOLUA::run_chunk( l, fileContent ) )
		{
			VLOG( 8 ) << "lua dofile: successfully ran " << fileName;
		}
		else
		{
			LOG( WARNING ) << "lua dofile: failure in " << fileName;
		}
	}
	else
	{
		LOG( INFO ) << "lua dofile: Invalid number of arguments.";
	}

	return 0;
}


//////////////////////////////////////////////////////////////////////////
// Redirects loadfile to use physfs.
extern "C"
int luaLoadFile( lua_State* l )
{
	int	nargs	=	lua_gettop( l );
	if( nargs==1 && lua_isstring( l, 1 ) )
	{
		std::string	fileName	=	lua_tostring( l, 1 );
		LOG( INFO ) << "lua loadfile: " << fileName;
		std::string	fileContent	=	FileSystem::ReadFileAsString( fileName );

		if( OOLUA::load_chunk( l, fileContent ) )
		{
			VLOG( 8 ) << "lua loadfile: successfully loaded " << fileName;
		}
		else
		{
			LOG( WARNING ) << "lua loadfile: failure in " << fileName;
		}
	}
	else
	{
		LOG( INFO ) << "lua loadfile: Invalid number of arguments.";
	}

	return 0;
}
*/


// Overloads to lua base functionality.
static const struct luaL_Reg	luaLibOverload[]	=
{
	{"print",		luaPrint},
	{"log",			luaPrint},		// alias for print.
//	{"dofile",		luaDoFile},
//	{"loadfile",	luaLoadFile},
	{nullptr,		nullptr}
};


//////////////////////////////////////////////////////////////////////////
Core::Script::Script()
{
	mpState	=	luaL_newstate();
	luaL_openlibs( mpState );

#ifdef ENABLE_DEVBUILD
	luabridge::setHideMetatables( false );
#endif

	// Replace various globals.
	lua_getglobal( mpState, "_G" );
	luaL_setfuncs( mpState, luaLibOverload, 0 );
	lua_pop( mpState, 1 );
}


Core::Script::~Script()
{
}


bool Core::Script::Load( const std::string& script )
{
	std::string	scriptData	=	FileSystem::ReadFileAsString( script );
	return luaL_loadstring( mpState, scriptData.c_str() )==LUA_OK;
}


bool Core::Script::Run( const std::string& script )
{
	std::string	scriptData	=	FileSystem::ReadFileAsString( script );
	return luaL_dostring( mpState, scriptData.c_str() )==LUA_OK;
}


bool Core::Script::Call( const std::string& function )
{
	luabridge::LuaRef	refItem	=	luabridge::getGlobal( mpState, function.c_str() );
	if( refItem )
	{
		try
		{
			refItem();
			return true;
		}
		catch( luabridge::LuaException e )
		{
			LOG( ERROR ) << e.what();
		}
	}

	return false;
}
